const http = require('http')
const socketIO = require('socket.io')
const { loger } = require('@daelui/oxkit')

const run = function ({ app, config }) {
  const httpServer = http.Server(app)
  // 创建socket.io 服务
  const io = socketIO(httpServer, Object.assign({
    maxHttpBufferSize: 2 * 1e9, // 最大2G文件
    pingTimeout: 60000,
    httpCompression: {
      // Engine.IO options
      threshold: 2048, // defaults to 1024
      // Node.js zlib options
      chunkSize: 8 * 1024, // defaults to 16 * 1024
      windowBits: 14, // defaults to 15
      memLevel: 7, // defaults to 8
    },
    connectionStateRecovery: {
      // the backup duration of the sessions and the packets
      maxDisconnectionDuration: 5 * 60 * 1000,
      // whether to skip middlewares upon successful recovery
      skipMiddlewares: true,
    }
  }, config.chat))

  let wsindex = 0
  io.on('connection', (socket) => {
    // 客户端重连
    if (socket.recovered) {
      loger.log(socket.nickname + ': ' + '重连成功')
      return true
    }
    // 客户端连接完成
    socket.emit('connected', { wsindex })
    socket.wsindex = wsindex
    wsindex += 1
    // 客户端登录
    socket.on('login' , ({ nickname, room } = {}) => {
      socket.room = room
      socket.nickname = nickname
      let sockets = getRoomSockets(room)
      sockets.forEach(sock => {
        sock.emit('logged' , {nickname , isLogin: true})
      })
      loger.log((nickname ? nickname + ': ' : '') + '登录成功')
    })
    // 客户端断开
    socket.on('disconnecting', (reason) => {
      let nickname = socket?.nickname
      if (nickname) {
        let sockets = getRoomSockets(socket?.room)
        sockets.forEach(sock => {
          sock.emit('logout' , {nickname, isLogin: false})
        })
        delete socket[nickname]
      }
      loger.log((nickname ? nickname + ': ' : '') + '断开连接')
    })
    // 接收客户端消息
    socket.on('chat', ({ msg, type, code, fid }) => {
      socket.broadcast.emit('response_chat', {
        room: socket.room,
        nickname: socket.nickname,
        msg: msg,
        type: type,
        fid: fid,
        code: code,
        wsindex: socket.wsindex,
        time: Date.now()
      })
    })
    // 客户端请求下载文件
    socket.on('file_request_download', ({ msg, type, fid }) => {
      // 向客户端广播拉取文件请求
      io.sockets.emit('file_pull_from_client', {
        filename: msg,
        type: type,
        fid: fid,
        wsid: socket.id,
        time: Date.now()
      })
    })
    // 接收客户端传入的文件
    socket.on('file_push_to_server', (buffer, data) => {
      let ws = io.sockets.sockets.get(data.wsid)
      if (ws) {
        loger.log('推送文件至客户端')
        ws.emit('file_push_to_client', buffer, data)
      }
    })
  })

  // 获取房间内的socket
  function getRoomSockets (room) {
    let ids = Array.from(io.sockets.sockets.keys())
    let sockets = []
    ids.forEach(id => {
      let ws = io.sockets.sockets.get(id)
      if (ws.room === room || (!room && !ws.room)) {
        sockets.push(ws)
      }
    })
    return sockets
  }

  httpServer.listen(config.constant.socketPort, function() {
    setTimeout(() => {
      console.log('DChat Server is running on: ws://localhost:' + config.constant.socketPort)
    }, 500)
  })
}

module.exports = {
  run
}
